package org.altervista.cp.thinjdbc.wrappers;

import java.sql.SQLException;
import java.sql.SQLWarning;

import org.altervista.cp.thinjdbc.util.LogHelper;

public abstract class Statement extends Wrapper<java.sql.Statement>
		implements java.sql.Statement {

	private static final LogHelper logger = new LogHelper(
			Statement.class);

	static Statement newInstance(java.sql.Statement stm) {
		return _GENERATOR.generate(stm);
	}

	public void close() {
		try {
			if (_rw != null) {
				_rw.close();
			}
		} catch (SQLRuntimeException e) {
		}
		try {
			java.sql.Statement sw = unwrap();
			if (sw != null) {
				logger.debug("closing statement");
				sw.close();
			}
		} catch (SQLException e) {
			throw new SQLRuntimeException(e);
		} finally {
			_cw = null;
			_rw = null;
			_GENERATOR.release(this);
		}
	}

	public ResultSet executeQuery(String sql) {
		try {
			logger.debug("Executing query statement:\n{0}", sql);

			_rw = ResultSet.newInstance(unwrap().executeQuery(sql));
			_rw.setStatementWrapper(this);
			return _rw;
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeQuery(sql);
		}
	}

	public boolean execute(String sql, int autoGeneratedKeys) {
		try {
			logger.debug("Executing update statement:\n{0}\ncolumnNames: {1}",
					sql, autoGeneratedKeys);

			return unwrap().execute(sql, autoGeneratedKeys);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return execute(sql, autoGeneratedKeys);
		}
	}

	public boolean execute(String sql, int[] columnIndexes) {
		try {
			logger.debug("Executing update statement:\n{0}\ncolumnNames: {1}",
					sql, columnIndexes);

			return unwrap().execute(sql, columnIndexes);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return execute(sql, columnIndexes);
		}
	}

	public boolean execute(String sql, String[] columnNames) {
		try {
			logger.debug("Executing update statement:\n{0}\ncolumnNames: {1}",
					sql, columnNames);

			return unwrap().execute(sql, columnNames);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return execute(sql, columnNames);
		}
	}

	public boolean execute(String sql) {
		try {
			logger.debug("Executing statement:\n{0}", sql);

			return unwrap().execute(sql);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return execute(sql);
		}
	}

	public int[] executeBatch() {
		try {
			logger.debug("Executing batch");
			return unwrap().executeBatch();
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeBatch();
		}
	}

	public int executeUpdate(String sql, int autoGeneratedKeys) {
		try {
			logger.debug(
					"Executing update statement:\n{0}\nautoGeneratedKeys: {1}",
					sql, autoGeneratedKeys);

			return unwrap().executeUpdate(sql, autoGeneratedKeys);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeUpdate(sql, autoGeneratedKeys);
		}
	}

	public int executeUpdate(String sql, int[] columnIndexes) {
		try {
			logger.debug(
					"Executing update statement:\n{0}\ncolumnIndexes: {1}",
					sql, columnIndexes);

			return unwrap().executeUpdate(sql, columnIndexes);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeUpdate(sql, columnIndexes);
		}
	}

	public int executeUpdate(String sql, String[] columnNames) {
		try {
			logger.debug("Executing update statement:\n{0}\ncolumnNames: {1}",
					sql, columnNames);

			return unwrap().executeUpdate(sql, columnNames);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeUpdate(sql, columnNames);
		}
	}

	public int executeUpdate(String sql) {
		try {
			logger.debug("Executing update statement:\n{0}", sql);

			return unwrap().executeUpdate(sql);
		} catch (SQLException e) {
			_cw.rewrap(e);
			return executeUpdate(sql);
		}
	}

	public Connection getConnection() {
		return _cw;
	}

	public ResultSet getGeneratedKeys() {
		try {
			return ResultSet.newInstance(unwrap().getGeneratedKeys());
		} catch (SQLException e) {
			throw new SQLRuntimeException(e);
		}
	}

	public ResultSet getResultSet() {
		return _rw;
	}

	public abstract void addBatch(String sql);

	public abstract void cancel();

	public abstract void clearBatch();

	public abstract void clearWarnings();

	public abstract int getFetchDirection();

	public abstract int getFetchSize();

	public abstract int getMaxFieldSize();

	public abstract int getMaxRows();

	public abstract boolean getMoreResults();

	public abstract boolean getMoreResults(int current);

	public abstract int getQueryTimeout();

	public abstract int getResultSetConcurrency();

	public abstract int getResultSetHoldability();

	public abstract int getResultSetType();

	public abstract int getUpdateCount();

	public abstract SQLWarning getWarnings();

	public abstract void setCursorName(String name);

	public abstract void setEscapeProcessing(boolean enable);

	public abstract void setFetchDirection(int direction);

	public abstract void setFetchSize(int rows);

	public abstract void setMaxFieldSize(int max);

	public abstract void setMaxRows(int max);

	public abstract void setQueryTimeout(int seconds);

	void setConnectionWrapper(Connection cw) {
		_cw = cw;
	}

	void setResultSetWrapper(ResultSet rw) {
		_rw = rw;
	}

	private Connection _cw;
	private ResultSet _rw;

	private static final _ProxyGenerator<Statement> _GENERATOR = new _ProxyGenerator<Statement>(
			Statement.class);

}
